
//Utility to mimic standard OOP behaviour... JavaScript behaves a little different usually because of its architecture, especially concerning heritage.
//This script was copied from http://www.kevlindev.com/tutorials/javascript/inheritance/ and his copyright terms apply.

extend = function(subClass, baseClass) {
	function inheritance() {}
	inheritance.prototype = baseClass.prototype;
	
	subClass.prototype = new inheritance();
	subClass.prototype.constructor = subClass;
	subClass.baseConstructor = baseClass;
	subClass.superClass = baseClass.prototype;
}

//Javascript code to write/read files in Firefox, copyright Andreas Halter

function readFile(str_Filename){ 
        try{
           var obj_File = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
           obj_File.initWithPath(str_Filename);
 
           var obj_InputStream =  Components.classes["@mozilla.org/network/file-input-stream;1"].createInstance(Components.interfaces.nsIFileInputStream);
           obj_InputStream.init(obj_File,0x01,0444,null);
 
           var obj_ScriptableIO = Components.classes["@mozilla.org/scriptableinputstream;1"].createInstance(Components.interfaces.nsIScriptableInputStream);
           obj_ScriptableIO.init(obj_InputStream);
        } catch (e) { alert(e); }
 
        try {
                var str = obj_ScriptableIO.read(obj_File.fileSize-1);
        } catch (e) { dump(e); }
        obj_ScriptableIO.close();
        obj_InputStream.close();
        return str;
}

function writeFile(str_Buffer,str_Filename){
    try{
        var obj_File = Components.classes["@mozilla.org/file/local;1"].createInstance(Components.interfaces.nsILocalFile);
        obj_File.initWithPath(str_Filename);
        if(!obj_File.exists()) obj_File.create(0x00,0644);
    } catch (e) { alert(e); }
    try {
        var obj_Transport = Components.classes["@mozilla.org/network/file-output-stream;1"].createInstance(Components.interfaces.nsIFileOutputStream);
        obj_Transport.init( obj_File, 0x04 | 0x08 | 0x10, 064, 0 );
        obj_Transport.write(str_Buffer,str_Buffer.length);
        obj_Transport.close();
    } catch (e) {
        alert(e);
    }
}

function selectFile(mode,title){
   var nsIFilePicker = Components.interfaces.nsIFilePicker;
   var fp = Components.classes["@mozilla.org/filepicker;1"].createInstance(nsIFilePicker);
   fp.init(window, title, nsIFilePicker[mode]);
   var res=fp.show();
   if (res==nsIFilePicker.returnOK) return fp.file;
   else return undefined;
}


//From this point on, everything is (c) 2006 Hans Schmucker

//A simple extension to the Array class, so that we can swap two elements:
Array.prototype.swap=function(a, b){
	var tmp=this[a];
	this[a]=this[b];
	this[b]=tmp;
}

//A simple extension to the Array class, so that we can move an element:
Array.prototype.move=function(src, dest){
	var tmp=this[src];
	this.splice(src,1);
	this.splice(dest,0,tmp);
}




		
//In JS Classes are declared as functions, again for historial reasons. Actually we are creating a constructor with the function keyword and lateron extend it to include methods.
function media(parameterObject){
	//All variables inside a constructor are private member variables. Unfortunately, when using Java-like inheritance, these variables are statically assigned to the class and therefore unusable.
	//Public variables are declared (and used) by prefixing them with "this.".

	//Private (static):
		//releaseYear needs further testing... if it's <100 then the year was probably given short (98) instead of long (1998), since we'll need this a few times we define it as a private member function.
		yearYYtoYYYY=function(yy){
			if(yy>=0 && yy<100){
				switch( Math.floor(yy/50)){
					case 1: yy+=1900; break;
					default: yy+=2000; break;
				}
			}
			return yy;
		}
	
	//Constructor
		//We test if the parameterObject has a property that we can use as the initial value. If it doesn't contain one, we just use a default value.
		if(parameterObject["name"]!=undefined) this.setName(parameterObject["name"]); else this.setName("Unknown Title");
		if(parameterObject["releaseYear"]!=undefined) this.setReleaseYear(parameterObject["releaseYear"]); else this.setReleaseYear(-1);
		if(parameterObject["length"]!=undefined) this.setLength(parameterObject["length"]); else this.setLength(-1);
		if(parameterObject["artist"]!=undefined) this.setArtist(parameterObject["artist"]); else this.setArtist("Unknown Artist");
		
}

	//Public Methods:
		media.prototype.toString=function(){
			//Serializes the whole object content into one JSON compatible string.
			return "\"name\":\""+(this.getName())+"\", \"releaseYear\":"+this.getReleaseYear()+", \"length\":"+this.getLength()+", \"artist\":\""+this.getArtist()+"\"";
		}
	
		media.prototype.setName=function(par){ this.name=par; }
		media.prototype.getName=function(){ return this.name; }
		
		media.prototype.setReleaseYear=function(par){ this.releaseYear=yearYYtoYYYY(parseInt(par)); }
		media.prototype.getReleaseYear=function(){ return this.releaseYear; }
		
		media.prototype.setLength=function(par){ this.length=parseInt(par); }
		media.prototype.getLength=function(){ return this.length; }	
		
		media.prototype.setArtist=function(par){ this.artist=par; }
		media.prototype.getArtist=function(){ return this.artist; }	

		
		
		
		
		
//We first use the extend utility to create a dvd class which references all media properties,
extend(dvd, media); function dvd(parameterObject){
	//Constructor
		//We first have to call the initial constructor. "Call" makes sure it gets executed in the scope of "dvd".
		dvd.baseConstructor.call(this, parameterObject);
		if(parameterObject["lang"]!=undefined) this.setLang(parameterObject["lang"]); else this.setLang("Unknown Language");
}

	//Public Methods:
		dvd.prototype.setLang=function(par){
			this.lang=par;
		}
		
		dvd.prototype.getLang=function(){
			return this.lang;
		}
		
		dvd.prototype.toString=function(){
			//We use the static superClass property to get to the superClass's toString method, which we then extend.
			return dvd.superClass.toString.call(this)+", \"lang\":\""+this.getLang()+"\"";
		}
	



function dvdlist(listString, filePath, treeEm){
	this.entries=new Array();
	this.filePath="";
	this.treeElement=undefined;
	
	if(listString!=undefined) this.applyList(listString);
	if(filePath!=undefined) this.setPath(filePath);
	if(treeEm!=undefined) this.setTree(treeEm);
}

	//Public Methods:
		dvdlist.prototype.applyList=function(par){
			listStringentries=par.split("&");
			for(i=0;i<listStringentries.length;i++){
				//Looks strange to use eval ("execute") to turn a string into a data object? It's actually sortof common in AJAX applications, just lookup JSON.
				c=eval("( {"+listStringentries[i]+"} )");
				
				this.entries[i]=new dvd({"name":c["name"],"releaseYear":c["releaseYear"],"length":c["length"],"artist":c["artist"],"lang":c["lang"]});
			}
		}

		dvdlist.prototype.toString=function(){
			resString="";
			for(j=0;j<this.getLength();j++){
				resString=resString+(j==0?"":" & ")+this.getEntry(j).toString();
			}
			
			return resString;
		}

		dvdlist.prototype.appendEntry=function(parameterObject){this.entries.push(new dvd(parameterObject));}
		dvdlist.prototype.removeEntry=function(par){this.entries.splice(par,1);}
		dvdlist.prototype.swapEntries=function(src,dest){this.entries.swap(src,dest);}
		dvdlist.prototype.moveEntry=function(src,dest){this.entries.move(src,dest);}
		dvdlist.prototype.getEntry=function(idx){return this.entries[idx];}
		dvdlist.prototype.getLength=function(idx){return this.entries.length;}
		
		dvdlist.prototype.setPath=function(setPathString){ this.filePath=setPathString; }
		dvdlist.prototype.getPath=function(){ return this.filePath; }		

		dvdlist.prototype.setTree=function(treeElm){ this.treeElement=treeElm; }
		dvdlist.prototype.getTree=function(){ return (this.treeElement); }		

		dvdlist.prototype.save=function(){
			if(this.filePath==undefined || this.filePath=="" || this.filePath==false){
				fileObj=selectFile("modeSave","Save DVD Database to");
				if(fileObj!=undefined) this.filePath=fileObj.path;
			}
			if(this.filePath!=undefined && this.filePath!="" && this.filePath!=false) writeFile(this.toString()+"  ",this.filePath);
		}

		dvdlist.prototype.load=function(){
			if(this.filePath==undefined || this.filePath=="" || this.filePath==false){
				fileObj=selectFile("modeLoad","Load DVD Database from");
				if(fileObj!=undefined) this.filePath=fileObj.path;
			}
			if(this.filePath!=undefined && this.filePath!="" && this.filePath!=false) srcStr=readFile(this.filePath);
			if(srcStr!=undefined){
				this.applyList(srcStr);
				this.updateTree();
			}
		}

		dvdlist.prototype.unselectTree=function(){
			this.getTree().currentIndex= -1;
			document.getElementById("editFieldTitle").value="";
			document.getElementById("editFieldArtist").value="";
			document.getElementById("editFieldLength").value="";
			document.getElementById("editFieldLang").value="";
			document.getElementById("editFieldReleaseYear").value="";
		}
		
		dvdlist.prototype.updateTree=function(){
				
				this.getTree().currentIndex= -1;
				
				delitems=this.getTree().getElementsByTagName("treeitem");
				while(delitems.length>0){
					delitems[0].parentNode.removeChild(delitems[0]);
					delitems=this.getTree().getElementsByTagName("treeitem");
				}

				
				for(k=0;k<this.getLength();k++){

					item=document.createElement("treeitem");
					
					cell1=document.createElement("treecell");cell1.setAttribute("label",String(k));
					cell2=document.createElement("treecell");cell2.setAttribute("label",dvdUserList.getEntry(k).getName());
					cell3=document.createElement("treecell");cell3.setAttribute("label",dvdUserList.getEntry(k).getArtist());
					cell4=document.createElement("treecell");cell4.setAttribute("label",dvdUserList.getEntry(k).getReleaseYear());
					cell5=document.createElement("treecell");cell5.setAttribute("label",dvdUserList.getEntry(k).getLength());
					cell6=document.createElement("treecell");cell6.setAttribute("label",dvdUserList.getEntry(k).getLang());
					row=document.createElement("treerow");
					
					row.appendChild(cell1);
					row.appendChild(cell2);
					row.appendChild(cell3);
					row.appendChild(cell4);
					row.appendChild(cell5);
					row.appendChild(cell6);
					
					item.appendChild(row);
					
					this.getTree().getElementsByTagName("treechildren")[0].appendChild(item);
				}
			
			this.unselectTree();
		}

		dvdlist.prototype.showEditField=function(){
			if(dvdUserList.getTree().currentIndex>=0){
				isitem=dvdUserList.getEntry(dvdUserList.getTree().currentIndex);
				
				document.getElementById("editFieldTitle").value=isitem.getName();
				document.getElementById("editFieldArtist").value=isitem.getArtist();
				document.getElementById("editFieldLength").value=isitem.getLength();
				document.getElementById("editFieldLang").value=isitem.getLang();
				document.getElementById("editFieldReleaseYear").value=isitem.getReleaseYear();
			}
		}
		
		dvdlist.prototype.saveEditField=function(){
			if(dvdUserList.getTree().currentIndex>=0){
				isitem=dvdUserList.getEntry(dvdUserList.getTree().currentIndex);
				
				isitem.setName(document.getElementById("editFieldTitle").value);
				isitem.setArtist(document.getElementById("editFieldArtist").value);
				isitem.setLength(document.getElementById("editFieldLength").value);
				isitem.setLang(document.getElementById("editFieldLang").value);
				isitem.setReleaseYear(document.getElementById("editFieldReleaseYear").value);
				dvdUserList.updateTree();
			}
		}		
		
		
		
		
		

	function init(){
		dvdUserList=new dvdlist(undefined,undefined,document.getElementById("dvddbtree"));
		dvdUserList.setTree(document.getElementById("dvddbtree"));
	}

function UI_action(evt){
	switch(evt.target.id){
		case "load":
			dvdUserList.load();
			break;
		case "save":
			dvdUserList.save();
			break;
		case "append":
			dvdUserList.appendEntry({});
			dvdUserList.updateTree();
			break;
		case "remove":
			lpos=dvdUserList.getTree().currentIndex;
			if(lpos>=0){
				dvdUserList.removeEntry(lpos);
				dvdUserList.updateTree();
			}
			break;
		case "dvddbtree":
			dvdUserList.showEditField();
			break;
		case "update":
			dvdUserList.saveEditField();
			break;
		default:
			break;
	}
}
